/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package technotheist.geo.map.vector;

import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import technotheist.geo.map.MapUV;
import technotheist.geo.map.VectorMap;
import technotheist.geo.map.scalar.FloatMap;

/**
 *
 * @author Mitchel Strachan
 */
public class Float2Map extends FloatMap implements VectorMap<Vector2f> {

    public static final int VEC_SIZE = 2;
    public final int layers;

    public Float2Map(int sideLength) {
        this(sideLength, 1);
    }
    public Float2Map(int sideLength, int layers) {
        super(sideLength, 2);
        this.layers = layers;
    }

    @Override
    public Vector2f get(int p, int u, int v, Vector2f store) {
        return get(p,u,v,0,store);
    }

    @Override
    public Vector2f get(int p, int u, int v, int layer, Vector2f store) {
        int i = index(p, u, v, layer);
        Vector2f vec = store == null ? new Vector2f() : store;
        vec.x = getFloat(i++);
        vec.y = getFloat(i);
        return vec;
    }

    @Override
    public void set(int p, int u, int v, Vector2f value) {
        set(p,u,v,0,value);
    }

    @Override
    public void set(int p, int u, int v, int layer, Vector2f value) {
        int i = index(p, u, v, layer);
        setFloat(i++, value.x);
        setFloat(i, value.y);
    }

    @Override
    public Vector2f getNor(int p, float u, float v, Vector2f store) {
        return getNor(p,u,v,0,store);
    }

    @Override
    public Vector2f getNor(int p, float u, float v, int layer, Vector2f store) {
        return get(p, u * (sideLength + 1), v * (sideLength + 1), layer, store);
    }

    @Override
    public Vector2f get(int p, float u, float v, Vector2f store) {
        return get(p, u, v, 0, store);
    }

    @Override
    public Vector2f get(int p, float u, float v, int layer, Vector2f store) {
        Vector2f vec = store == null ? new Vector2f() : store;
        int u0 = (int) FastMath.floor(u);
        int v0 = (int) FastMath.floor(v);

        float du = u - u0;
        float dv = v - v0;

        int i00 = index(p, u0, v0, layer);
        int i10 = index(p, u0, v0, layer);
        int i01 = index(p, u0, v0, layer);
        int i11 = index(p, u0, v0, layer);

        float d00 = (1 - du) * (1 - dv);
        float d10 = du * (1 - dv);
        float d01 = (1 - du) * dv;
        float d11 = du * dv;

        vec.x = getFloat(i00) * d00
                + getFloat(i10) * d10
                + getFloat(i01) * d01
                + getFloat(i11) * d11;
        vec.y = getFloat(i00 + 1) * d00
                + getFloat(i10 + 1) * d10
                + getFloat(i01 + 1) * d01
                + getFloat(i11 + 1) * d11;
        return vec;
    }

    public Vector2f get(int index, Vector2f store) {
        return get(index, 0, store);
    }
    public void set(int index, Vector2f value) {
        set(index, 0, value);
    }

    public Vector2f get(int index, int layer, Vector2f store) {
        int i = index * components + layer * VEC_SIZE;
        Vector2f vec = store == null ? new Vector2f() : store;
        vec.x = getFloat(i++);
        vec.y = getFloat(i++);
//        vec.z = getFloat(i++);
//        vec.w = getFloat(i++);
        return vec;
    }

    public void set(int index, int layer, Vector2f value) {
        int i = index * components + layer * VEC_SIZE;
        setFloat(i++, value.x);
        setFloat(i++, value.y);
//        setFloat(i++, value.z);
//        setFloat(i++, value.w);
    }
    public int index(int p, int u, int v, int layer) {
        if (layer < 0 || layer >= layers) {
            throw new IllegalArgumentException("layer must be between 0 and " + layers);
        }
        return index(p, u, v) + layer * VEC_SIZE;
    }

    @Override
    public Vector2f get(MapUV mp, Vector2f store) {
        return getNor(mp.panel(), mp.u, mp.v, store);
    }

    @Override
    public Vector2f get(MapUV mp, int layer, Vector2f store) {
        return getNor(mp.panel(), mp.u, mp.v, layer, store);
    }
}
